package com.lcf.framework.utils;

import com.lcf.framework.annotation.DictFile;
import com.lcf.framework.exception.SysException;
import com.lcf.framework.utils.oss.OssUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 描述：实体类翻译
 *
 * @author lcf
 * @since 2025/4/1 20:17
 */
@Slf4j
@Component
public class EntityFileRelativeUtils {
    //文件相对路径
    private static final ThreadLocal<List<String>> FILE_PATH = ThreadLocal.withInitial(ArrayList::new);

    /**
     * 翻译
     */
    public Object translate(Object result) {
        try {
            // 阶段1：扫描所有需要翻译的字段（字典+表字段+图片）
            scanAndProcess(result, true);

            // 阶段3：统一填充翻译值（表字段+图片）
            scanAndProcess(result, false);
        } finally {
            FILE_PATH.remove();
        }

        return result;
    }

    /**
     * 判断是否为JDK类
     */
    public boolean isNotJdkClass(Class<?> clazz) {
        return !clazz.getName().startsWith("java.")
                && !clazz.getName().startsWith("javax.")
                && !clazz.getName().startsWith("org.springframework.")
                && !(clazz.isArray() && clazz.getComponentType() == byte.class);
    }

    /**
     * 统一扫描和处理入口
     *
     * @param obj         处理对象
     * @param isScanPhase 是否为扫描阶段（true=收集主键值，false=填充翻译值）
     */
    private void scanAndProcess(Object obj, boolean isScanPhase) {
        processInternal(obj, new WeakHashMap<>(), isScanPhase);
    }

    /**
     * 递归处理核心逻辑
     */
    private void processInternal(Object obj, Map<Object, Boolean> processedMap, boolean isScanPhase) {
        if (obj == null || processedMap.containsKey(obj)) {
            return;
        }

        //防止递归处理对象时出现循环引用导致的无限循环，并确保每个对象只被处理一次。
        processedMap.put(obj, true);

        // 处理集合类型
        if (obj instanceof Collection<?> collection) {
            collection.forEach(item -> processInternal(item, processedMap, isScanPhase));
            return;
        }

        // 处理数组类型
        if (obj.getClass().isArray()) {
            for (Object item : (Object[]) obj) {
                processInternal(item, processedMap, isScanPhase);
            }
            return;
        }

        // 处理单个对象的字段
        Class<?> clazz = obj.getClass();
        if (isNotJdkClass(clazz)) {
            for (Field field : getDeclaredFields(clazz)) {
                handleField(obj, field, processedMap, isScanPhase);
            }
        }
    }

    /**
     * 统一字段处理逻辑
     */
    private void handleField(Object obj, Field field, Map<Object, Boolean> processedMap, boolean isScanPhase) {
        try {
            field.setAccessible(true);
            Object fieldValue = field.get(obj);

            //处理@Image注解，将图片相对路径转为绝对路径，只处理 String 类型字段
            if (field.isAnnotationPresent(DictFile.class) && field.getType() == String.class && fieldValue != null) {
                String imagePath = (String) fieldValue;
                if (isScanPhase) {
                    // 将字段信息加入批量处理上下文
                    FILE_PATH.get().add(imagePath);
                } else {
                    Map<String, String> relativeUrlMap = OssUtils.getRelativeMap(FILE_PATH.get());
                    field.set(obj, relativeUrlMap.get(imagePath));
                }
            }

            // 递归处理字段值
            processInternal(fieldValue, processedMap, isScanPhase);
        } catch (Exception e) {
            throw new SysException(e);
        }
    }

    private List<Field> getDeclaredFields(Class<?> clazz) {
        return Arrays.asList(clazz.getDeclaredFields());
    }
}
